home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / std / c / 392 < prev    next >
Encoding:
Internet Message Format  |  1996-08-06  |  4.6 KB

  1. Path: keats.ugrad.cs.ubc.ca!not-for-mail
  2. From: c2a192@ugrad.cs.ubc.ca (Kazimir Kylheku)
  3. Newsgroups: comp.lang.c,comp.std.c,comp.lang.c++
  4. Subject: Re: Floating Point arithmetic problem
  5. Date: 14 Feb 1996 19:27:01 -0800
  6. Organization: Computer Science, University of B.C., Vancouver, B.C., Canada
  7. Message-ID: <4fu965INNq3g@keats.ugrad.cs.ubc.ca>
  8. References: <c968da6jzm.fsf@damayanti.india.ti.com>
  9. NNTP-Posting-Host: keats.ugrad.cs.ubc.ca
  10.  
  11. In article <c968da6jzm.fsf@damayanti.india.ti.com>,
  12. Kuntal Shah <kuntal@india.ti.com> wrote:
  13.  >
  14.  >I am having a wierd problem with floating point arithmetic. Gurus on
  15.  >the net, please bail me out. I am working on the SUN 4.1.x platform.
  16.  >
  17.  >I have a "double" variable say d to which  I need to add certain float
  18.  >numbers  of  moderate magnitude (say   less than 10000). This addition
  19.  >occurs in a loop in my program which  get executed more than a million
  20.  >times depending on my testcase.
  21.  >
  22.  >    { /* loop begin */
  23.  >
  24.  >        /* some code */
  25.  >
  26.  >    d = d + f; /* f < 10000 */
  27.  
  28. Ouch. Don't do that. The accumulated truncation error will kill ya.
  29.  
  30. This can be fixed by using an integer counter which you multiply by a floating
  31. point scale factor, like this:
  32.  
  33. #define STEPS 100000
  34.  
  35. {
  36.     int i;    /* loop counter    */
  37.     int t;    /* parameter    */
  38.  
  39.     for (i = 0; i < STEPS; i++) {
  40.         t = (double) i / STEPS;
  41.         /* ... */
  42.     }
  43. }
  44.  
  45. Here the loop counter iterates through 100,000 steps, and the floating
  46. point parameter t varies from 0 to 1. It does not suffer from cumulative
  47. truncation errors because it is recalculated from the precise integer value
  48. each time by a multiplication.
  49.  
  50.  >Now coming  to   the  problem. The  insignificant  digits   due to the
  51.  >floating  point representation keep  accruing and  there comes a stage
  52.  >when the accrued value exceeds 0.0001 which  results in failure of the
  53.  >if condition in the  above block of code,  when ideally no such  thing
  54.  >should have occurred.
  55.  >
  56.  >All I need is a solution that will  overcome this problem. Please bear
  57.  >in mind  that the  loop is executed  millions  of times and  hence any
  58.  >costly operation     within  the loop    with  drastically  bring down
  59.  >performance.
  60.  >
  61.  >I have a few options to overcome this problem :-
  62.  >
  63.  >* After each   addition,   covert  'd' to   an  unsigned   long  after
  64.  >  multiplying  by say 1e8, (thus   truncating the unnecessary digits),
  65.  >  and divide it by 1e8 to get back the original value.
  66.  >
  67.  >* After every few additions, say 1000, do the above operation.
  68.  >
  69.  >In  both the above operations,  a severe problem  would arise in cases
  70.  >when  the  value represented  is less  than  the value  asked for. For
  71.  >example, 
  72.  >
  73.  >   f= 213.22 would be represented as 213.2199999999999988631316228
  74.  >
  75.  >and  cutting off the last few  digits would result in negative accrual
  76.  >in the wrong run. Since I am not sure of the value of f till run time,
  77.  >I cannot solely depend on +ve or -ve accrual to happen.
  78.  >
  79.  >Do you have any  solution to this  problem? Ideally  I would  like the
  80.  >following answers :-
  81.  
  82. Try my above way of using an integer as a parameter. A 32-bit integer has a
  83. plentiful range for any number of iterations you are likely to attempt and can
  84. be thunked into floating point quite readily. On most workstations, the double
  85. type is 64-bit with a 52-bit mantissa can accomodate large 32-bit integers
  86. without truncation, so you should be OK regardless of what range of integers
  87. you convert to floating point.
  88.  
  89.  >* Is it possible to use bit wise operators (since  they are lot faster
  90.  >  than   other computations) to  remove  the least significant bits? I
  91.  >  tried doing this but wasn't all that effective.
  92.  
  93. I strongly discourage you from even contemplating this. Floating point
  94. representations can vary wildly from architecture to architecture. The bit
  95. operators are really intended for unsigned integer operands.
  96.  
  97.  >* Is it  possible to set  to zero,  say the last  10-15  digits of the
  98.  >  decimal part   without any effect  in the  long  run on  the 5 digit
  99.  >  precision I require?
  100.  
  101. Not easily. For one thing, the resulting number may not be representable in the
  102. machine's floating point format. The floating point format is typically binary,
  103. not decimal, and numbers that have terminating decimal digits in base ten may
  104. have repeating digits in base two.
  105.  
  106.  >* Is there any function  that can round  numbers  off to the  required
  107.  >  precision, ie,  can I specify 0.66666666666623345  to be rounded off
  108.  >  to  0.666666666667 without undergoing  the usual multiply, truncate,
  109.  >  divide flow.
  110.  
  111. No.
  112.  
  113. My advice: buy an undergraduate-level textbook on Numerical Analysis.
  114. A good book will explain floating point formats, coping with rounding and
  115. truncation errors and so forth, usually in the first chapter.
  116. -- 
  117.  
  118.